﻿Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.Xml
Imports System.IO

' This app is a TCP server
' It is used as a proxy to return a page from an internal web server
' Currently no encryption other than the authentication
' Use mainly for public content until full encyption added

Module MainMod
  Dim params As New XmlDocument
  Const DEFAULTPORT As Integer = 9080
  Dim loggingLevel As Integer = 0

  Sub Main()
    ' Start Log
    logInfo.logFileName = Path.Combine(Directory.GetCurrentDirectory, "nsWebProxy.log")
    logInfo.WriteLog("nsWebProxy Started " & Now)

    If Not File.Exists(Path.Combine(Directory.GetCurrentDirectory, "nsWebProxyParams.xml")) Then
      logInfo.WriteLog("params file nsWebProxyParams.xml not found.")
      Exit Sub
    End If

    Try
      ' Load program parameters
      params.Load(Path.Combine(Directory.GetCurrentDirectory, "nsWebProxyParams.xml"))
      Dim myPort As Integer = 0
      If params.SelectSingleNode("ProxySites/Port") IsNot Nothing AndAlso _
        params.SelectSingleNode("ProxySites/Port").Attributes("number") IsNot Nothing AndAlso _
        Integer.TryParse(params.SelectSingleNode("ProxySites/Port").Attributes("number").Value, myPort) Then
        ' port ok
      End If
      If myPort <= 0 Then
        myPort = DEFAULTPORT
      End If

      If params.SelectSingleNode("ProxySites/Logging") IsNot Nothing AndAlso _
        params.SelectSingleNode("ProxySites/Logging").Attributes("level") IsNot Nothing AndAlso _
        Integer.TryParse(params.SelectSingleNode("ProxySites/Logging").Attributes("level").Value, loggingLevel) Then
        ' get logging level
      End If

      Dim tcpServer As New TcpListener(IPAddress.Any, myPort)
      Dim tcpClient As TcpClient

      tcpServer.Start()

      logInfo.WriteLog("Start listening on " & myPort.ToString & " ...")

      ' wait for client connections
      Do While True
        tcpClient = tcpServer.AcceptTcpClient()
        Dim ipEnd As IPEndPoint = tcpClient.Client.RemoteEndPoint
        logInfo.WriteLog("Client connection request at " & Now & " from " & ipEnd.Address.ToString)
        Dim pclient As New proxyClient
        pclient.startClient(tcpClient)
      Loop

    Catch ex As Exception
      logInfo.WriteLog("Error @ " & Now)
      logInfo.WriteLog(ex.Message)
      logInfo.WriteLog(ex.StackTrace)
    End Try

  End Sub

  Public Class proxyClient
    Private _Client As TcpClient

    Public Sub startClient(ByVal inClient As TcpClient)
      _Client = inClient
      Dim cThread As Thread = New Thread(AddressOf serviceRequest)
      cThread.Start()
    End Sub

    Private Sub serviceRequest()
      Dim ns As NetworkStream = _Client.GetStream
      Dim readBuffer(1024) As Byte
      Dim readLen As Integer
      Dim requestMsg As StringBuilder = New StringBuilder()

      Dim wc As New nsWebClient
      Dim sAddress As String = ""
      Dim sQuery As String = ""
      Dim sResp As String = ""
      Dim respStream As Stream

      Try
        ns.ReadTimeout = 60000
        Do
          readLen = ns.Read(readBuffer, 0, 1024)
          requestMsg.Append(Encoding.ASCII.GetString(readBuffer, 0, readLen))
        Loop While ns.DataAvailable
        If loggingLevel > 0 Then
          logInfo.WriteLog("Client request at " & Now & " " & requestMsg.ToString)
        End If

      Catch ex As Exception
        logInfo.WriteLog("Error @ " & Now)
        logInfo.WriteLog(ex.Message)
        logInfo.WriteLog(ex.StackTrace)
      End Try
      ' the request should be a valid xml
      Try
        Dim xmlDoc As New XmlDocument
        xmlDoc.LoadXml(requestMsg.ToString)

        Dim siteName As String = xmlDoc.SelectSingleNode("Request").Attributes("site").Value
        Dim pageName As String = xmlDoc.SelectSingleNode("Request").Attributes("page").Value
        Dim reqData As String = xmlDoc.SelectSingleNode("Request/Data").InnerText

        ' Locate site and page in params
        Dim pageNode As XmlNode = params.SelectSingleNode("ProxySites/Site[@name='" & siteName & _
                                                        "']/Page[@name='" & pageName & "']")
        If pageNode Is Nothing Then
          Dim outStream As Byte() = System.Text.Encoding.ASCII.GetBytes("0")
          ns.Write(outStream, 0, outStream.Length)
        Else
          sAddress = pageNode.Attributes("url").Value
          If pageNode.Attributes("method").Value = "GET" Then
            'respStream = wc.OpenRead(sAddress & "?" & reqData)
            'Dim outStream(respStream.Length) As Byte
            'respStream.Read(outStream, 0, respStream.Length)
            Dim outStream As Byte() = wc.DownloadData(sAddress & "?" & reqData)
            ns.Write(outStream, 0, outStream.Length)
          Else
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
            Dim bPostData As Byte() = System.Text.Encoding.ASCII.GetBytes(reqData)
            Dim bResp As Byte() = wc.UploadData(sAddress, "POST", bPostData)
            sResp = System.Text.Encoding.ASCII.GetString(bResp)
          End If
        End If
      Catch ex As Exception
        logInfo.WriteLog("Error @ " & Now)
        logInfo.WriteLog(ex.Message)
        logInfo.WriteLog(ex.StackTrace)
      End Try

      Try
        ns.Close()
        _Client.Close()
      Catch ex As Exception
        logInfo.WriteLog("Error @ " & Now)
        logInfo.WriteLog(ex.Message)
        logInfo.WriteLog(ex.StackTrace)
      End Try
    End Sub
  End Class

End Module
